#pragma once

#include <iostream>

#include "Utility/Configuration/SGParameter.h"

TEST (SGParameterTest, ParametersIterator)
{
    SG::Utility::SGParameter parameters (R"(
            {
               "int_value" : 10, 
               "double_value": "2.0i",
               "bool_value" : true,
               "string_value" : "hello",
               "level1":
               {
                 "list_value":[ 3, "hi", false],
                 "tmp" : 5.0
               }
            }
            )");

    // 修改参数
    parameters.GetValue ("int_value").SetInt (666);

    // 使用迭代器方式访问 (会按key排序)
    auto i_parameter = parameters.begin ();
    EXPECT_TRUE ((*i_parameter).IsBool ());
    EXPECT_EQ ((*i_parameter).GetBool (), true);
    ++i_parameter;
    EXPECT_TRUE (i_parameter->IsComplex ());
    EXPECT_EQ (i_parameter->LookupOrDefault<std::complex<double>> (0).real (), 0);
    EXPECT_EQ (i_parameter->LookupOrDefault<std::complex<double>> (0).imag (), 2);
    ++i_parameter;
    // EXPECT_EQ (i_parameter.name (), std::string ("int_value"));
    EXPECT_TRUE (i_parameter->IsInt ());
    EXPECT_EQ (i_parameter->GetInt (), 666) << parameters.PrettyPrintJsonString ();

    // 使用中括号方式访问
    EXPECT_EQ (parameters["level1"]["tmp"].GetDouble (), 5.0);

    // 使用 GetValueByPath 访问
    EXPECT_EQ (parameters.GetValueByPath ("/level1/tmp").GetDouble (), 5.0);
    EXPECT_EQ (parameters.GetValueByPath ("/level1/list_value[0]").GetInt (), 3);
    EXPECT_EQ (parameters.GetValueByPath ("/level1/list_value[1]").GetString (), "hi");
    EXPECT_EQ (parameters.GetValueByPath ("/level1/list_value[2]").GetBool (), false);

    unsigned int size = 0;
    for (auto i = parameters.begin (); i != parameters.end (); i++)
    {
        // std::cout << i.name () << std::endl;
        size++;
    }

    EXPECT_EQ (size, 5);
}

TEST (SGParameterTest, Parameters_Constructor1)
{
    // Add 为对象添加子项
    // Append 为数组添加子项
    // Set 设置某项值
    SG::Utility::SGParameter p;
    p.AddString ("str", "hello");
    p.AddBool ("bool", false);

    p.AddDouble ("d", 66.6);

    SG::Utility::SGParameter sec;
    {
        sec.AddInt ("i", 666);

        sec.AddEmptyArray ("arr");
        sec.GetValue ("arr").Append (1);
        sec.GetValue ("arr").Append (2);
        sec.GetValue ("arr").Append (99.9);

        sec.GetValue ("i").SetInt (888);
    }

    p.AddValue ("sec", sec);

    EXPECT_EQ (
        R"({
    "BOOL": false,
    "D": 66.6,
    "SEC": {
        "ARR": [
            1,
            2,
            99.9
        ],
        "I": 888
    },
    "STR": "hello"
})",
        p.PrettyPrintJsonString ());
}

TEST (SGParameterTest, Parameters_Swap1)
{
    SG::Utility::SGParameter p1{ R"({"foo": 1.0})" };
    SG::Utility::SGParameter p2{ R"({"bar": false})" };
    p1.swap (p2);
    EXPECT_TRUE (p1.Has ("bar"));
    EXPECT_TRUE (p1["bar"].GetBool () == false);
    EXPECT_TRUE (p2.Has ("foo"));
    EXPECT_TRUE (p2["foo"].GetDouble () == 1.0);
}

TEST (SGParameterTest, Parameters_Reset1)
{
    SG::Utility::SGParameter p{ R"({"foo": {"bar": 1.0}})" };
    p.Reset ();
    EXPECT_EQ (p.WriteJsonString (), "{}");
}

TEST (SGParameterTest, Parameters_Reset2)
{
    SG::Utility::SGParameter p{ R"({"foo": {"bar": 1.0}})" };
    p.AddDouble("AAA", 123.0);
    ASSERT_TRUE (p.Has ("aaa"));
    ASSERT_TRUE (p.Has ("AAA"));
    ASSERT_TRUE (p.Has ("AAa"));
    ASSERT_TRUE (p.Has ("foo"));
    ASSERT_TRUE (p.Has ("Foo"));
}

TEST (SGParameterTest, Parameters_MoveAssignment1)
{
    SG::Utility::SGParameter p1{ R"({"foo": {"bar": 1.0}})" };
    SG::Utility::SGParameter p2{};
    p2 = std::move (p1);
    EXPECT_EQ (p1.WriteJsonString (), "{}");
    EXPECT_EQ (p2.WriteJsonString (), R"({"FOO":{"BAR":1.0}})");
}